// #include <stdio.h>
// #include <stdlib.h>
// #include <sys/types.h>
// #include <string.h>
// #include <unistd.h>
// #include <sys/wait.h>

// #define NUM 1024
// #define SIZE 32
// #define SEP " "
// char cmd_line[NUM];
// char *g_argv[SIZE];

// int main()
// {
//     while(1)
//     {
//         printf("[hbr@VM-16-9-centos linux]$");
//         fflush(stdout);
//         memset(cmd_line,0,sizeof(cmd_line));
//         if(fgets(cmd_line,sizeof(cmd_line),stdin)==NULL)
//         {
//             continue;
//         }
//         cmd_line[strlen(cmd_line)-1]='\0';
//         printf("echo: %s\n",cmd_line);
//         g_argv[0]=strtok(cmd_line,SEP);
//         int i=1;
//         while(g_argv[i++]=strtok(NULL,SEP));
//         if(strcmp(g_argv[0],"cd")==0)
//         {
//             if(g_argv[1]!=NULL)
//             {
//                 chdir(g_argv[1]);
//             }
//             continue;
//         }
//         else
//         {
//             pid_t id=fork();
//             if(id==0)
//             {
//                 printf("子进程执行下面命令\n");
//                 execvp(g_argv[0],g_argv);
//                 exit(1);
//             }
//             int status=0;
//             pid_t ret=waitpid(id,&status,0);
//             if(WIFEXITED(status))
//             {
//                 printf("子进程退出码：%d\n",WEXITSTATUS(status));
//             }
//         }
//     }
//     return 0;
// }

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>

#define NUM 4096
#define SIZE 64
#define SEP " " // 分隔符

// 保存完整的命令行字符串
char cmd_line[NUM];
// 保存打散之后的命令行字符串
char *g_argv[SIZE];

// shell运行原理：通过让子进程执行命令，父进程等待&解析命令
int main()
{
    // 0. 命令行解释器一定是一个常驻内存的进程，不退出
    while (1)
    {
        // 1. 打印出提示信息 [root@localhost myshell]#
        printf("[root@localhost myshell]#");
        fflush(stdout);
        memset(cmd_line, '\0', sizeof cmd_line);

        // 2. 获取用户的键盘输入 [输入的是各种指令和选项："ls -a -l"]
        if (fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
        {
            continue;
        }

        // 处理输入后的回车键导致的换行问题
        cmd_line[strlen(cmd_line) - 1] = '\0'; // 移除换行符

        // 3. 命令行解析 "ls -a -l" -> "ls" "-a" "-l"
        g_argv[0] = strtok(cmd_line, SEP); // 第一次调用，传入原始字符串
        int index = 1;
        while (g_argv[index++] = strtok(NULL, SEP));
        // 第二次还要解析原始字符串，传入 NULL
        // for debug
        // for(index=0;g_argv[index];index++)
        // {
        //     printf("g_argv[%d]: %s\n",index,g_argv[index]);
        // }
        // 4. 内置命令
        if (strcmp(g_argv[0], "cd") == 0)
        {
            if (g_argv[1] != NULL)
            {
                if (chdir(g_argv[1]) == -1)
                {
                    perror("Error changing directory");
                }
            }
            else
            {
                fprintf(stderr, "Usage: cd [directory]\n");
            }
            continue;
        }
        else if (strcmp(g_argv[0], "pwd") == 0)
        {
            char cwd[1024];
            if (getcwd(cwd, sizeof(cwd)) != NULL)
            {
                printf("%s\n", cwd);
            }
            else
            {
                perror("Error getting current directory");
            }
            continue;
        }
        else if (strcmp(g_argv[0], "echo") == 0)
        {
            for (index = 1; g_argv[index]; ++index)
            {
                printf("%s ", g_argv[index]);
            }
            printf("\n");
            continue;
        }

        // 5. fork()
        pid_t id = fork();
        if (id == 0)
        {
            printf("下面功能让子进程进行的\n");
            if (execvp(g_argv[0], g_argv) == -1)
            {
                perror("Error executing command");
                exit(1);
            }
        }
        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        if (ret > 0)
        {
            printf("exit code:%d\n", WEXITSTATUS(status));
        }
    }
    return 0;
}